home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
nethack.lha
/
nethack-3.1
/
src
/
save.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-11
|
20KB
|
865 lines
/* SCCS Id: @(#)save.c 3.1 93/01/07 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#include "lev.h"
#ifndef NO_SIGNAL
#include <signal.h>
#endif /* !NO_SIGNAL */
#if defined(EXPLORE_MODE) && !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
#include <fcntl.h>
#endif /* EXPLORE_MODE */
boolean hu; /* set during hang-up */
#ifdef MULDGN
#include "quest.h"
#endif
#ifdef MFLOPPY
extern struct finfo fileinfo[];
long bytes_counted;
static int count_only;
#else
extern boolean level_exists[];
#endif
#ifdef MICRO
int dotcnt; /* also used in restore */
#endif
#ifdef ZEROCOMP
static void FDECL(bputc, (UCHAR_P));
#endif
static void FDECL(savelevchn, (int, int));
static void FDECL(savedamage, (int,struct damage *, int));
static void FDECL(saveobjchn, (int,struct obj *, int));
static void FDECL(savemonchn, (int,struct monst *, int));
static void FDECL(savetrapchn, (int,struct trap *, int));
static void FDECL(savegenoinfo, (int));
static void FDECL(savegamestate, (int, int));
#ifdef MFLOPPY
static void FDECL(savelev0, (int,XCHAR_P,int));
static boolean NDECL(swapout_oldest);
static void FDECL(copyfile, (char *,char *));
#endif /* MFLOPPY */
#ifdef GCC_WARN
static long nulls[10];
#else
#define nulls nul
#endif
int
dosave()
{
clear_nhwindow(WIN_MESSAGE);
if(yn("Really save?") == 'n') {
clear_nhwindow(WIN_MESSAGE);
if(multi > 0) nomul(0);
} else {
clear_nhwindow(WIN_MESSAGE);
pline("Saving...");
mark_synch(); /* flush output */
hu = FALSE;
if(dosave0()) {
/* make sure they see the Saving message */
display_nhwindow(WIN_MESSAGE, TRUE);
exit_nhwindows("Be seeing you...");
terminate(0);
} else (void)doredraw();
}
return 0;
}
#ifndef NOSAVEONHANGUP
int
hangup() {
if(!hu) {
hu = TRUE;
(void) dosave0();
# ifndef VMS
terminate(1);
# endif
}
return 0;
}
#endif
/* returns 1 if save successful */
int
dosave0()
{
register int fd, ofd;
xchar ltmp;
#ifdef MFLOPPY
long fds, needed;
#endif
if (!SAVEF[0])
return 0;
#if defined(UNIX) || defined(VMS)
(void) signal(SIGHUP, SIG_IGN);
#endif
#ifndef NO_SIGNAL
(void) signal(SIGINT, SIG_IGN);
#endif
#if defined(MICRO) && defined(MFLOPPY)
if(!hu && !saveDiskPrompt(0)) return 0;
#endif
#ifdef EXPLORE_MODE
if(!hu && flags.window_inited) {
fd = open_savefile();
if (fd > 0) {
(void) close(fd);
clear_nhwindow(WIN_MESSAGE);
pline("There seems to be an old save file.");
if (yn("Overwrite the old file?") == 'n') return 0;
}
}
#endif
fd = create_savefile();
if(fd < 0) {
if(!hu) pline("Cannot open save file.");
(void) delete_savefile(); /* ab@unido */
return(0);
}
if(flags.moonphase == FULL_MOON) /* ut-sally!fletcher */
change_luck(-1); /* and unido!ab */
if(flags.friday13)
change_luck(1);
if(flags.window_inited)
clear_nhwindow(WIN_MESSAGE);
#ifdef MFLOPPY
if(!hu) {
dotcnt = 0;
curs(WIN_MAP, 1, 1);
putstr(WIN_MAP, 0, "Saving:");
}
/* make sure there is enough disk space */
savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
savegamestate(fd, COUNT_SAVE);
needed = bytes_counted;
for (ltmp = 1; ltmp <= maxledgerno(); ltmp++)
if (ltmp != ledger_no(&u.uz) && fileinfo[ltmp].where)
needed += fileinfo[ltmp].size + (sizeof ltmp);
# ifdef AMIGA
needed+=ami_wbench_iconsize(SAVEF);
# endif
fds = freediskspace(SAVEF);
if(needed > fds) {
if(!hu) {
pline("There is insufficient space on SAVE disk.");
pline("Require %ld bytes but only have %ld.", needed, fds);
}
flushout();
(void) close(fd);
(void) delete_savefile();
return 0;
}
#endif /* MFLOPPY */
bufon(fd);
savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
savegamestate(fd, WRITE_SAVE | FREE_SAVE);
for(ltmp = (xchar)1; ltmp <= maxledgerno(); ltmp++) {
if (ltmp == ledger_no(&u.uz)) continue;
#ifdef MFLOPPY
if (!fileinfo[ltmp].where) continue;
#else
if(!level_exists[ltmp]) continue;
#endif
#ifdef MICRO
if(!hu) {
curs(WIN_MAP, 8 + dotcnt++, 1);
putstr(WIN_MAP, 0, ".");
}
#endif
ofd = open_levelfile(ltmp);
if(ofd < 0) {
if(!hu) pline("Cannot read level %d.", ltmp);
(void) close(fd);
(void) delete_savefile();
if(!hu) done(TRICKED);
return(0);
}
minit(); /* ZEROCOMP */
getlev(ofd, hackpid, ltmp, FALSE);
(void) close(ofd);
bwrite(fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/
savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE); /* actual level*/
delete_levelfile(ltmp);
}
bclose(fd);
/* get rid of current level --jgm */
delete_levelfile(ledger_no(&u.uz));
delete_levelfile(0);
compress(SAVEF);
#ifdef AMIGA
ami_wbench_iconwrite(SAVEF);
#endif
return(1);
}
static void
savegamestate(fd, mode)
register int fd, mode;
{
int tmp; /* not register ! */
#ifdef MFLOPPY
count_only = (mode & COUNT_SAVE);
#endif
saveobjchn(fd, invent, mode);
saveobjchn(fd, migrating_objs, mode);
savemonchn(fd, migrating_mons, mode);
savegenoinfo(fd);
tmp = getuid();
bwrite(fd, (genericptr_t) &tmp, sizeof tmp);
bwrite(fd, (genericptr_t) &flags, sizeof(struct flag));
bwrite(fd, (genericptr_t) &u, sizeof(struct you));
save_dungeon(fd);
bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
savelevchn(fd, mode);
bwrite(fd, (genericptr_t) &moves, sizeof moves);
bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
#ifdef MULDGN
bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
#endif
bwrite(fd, (genericptr_t) spl_book,
sizeof(struct spell) * (MAXSPELL + 1));
save_artifacts(fd);
save_oracles(fd);
if(u.ustuck)
bwrite(fd, (genericptr_t) &(u.ustuck->m_id), sizeof u.ustuck->m_id);
bwrite(fd, (genericptr_t) pl_character, sizeof pl_character);
#ifdef TUTTI_FRUTTI
bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
bwrite(fd, (genericptr_t) ¤t_fruit, sizeof current_fruit);
savefruitchn(fd, mode);
#endif
savenames(fd);
save_waterlevel(fd);
bflush(fd);
}
#ifdef INSURANCE
void
savestateinlock()
{
int fd, hpid;
static boolean havestate = TRUE;
/* When checkpointing is on, the full state needs to be written
* on each checkpoint. When checkpointing is off, only the pid
* needs to be in the level.0 file, so it does not need to be
* constantly rewritten. When checkpointing is turned off during
* a game, however, the file has to be rewritten once to truncate
* it and avoid restoring from outdated information.
*
* Restricting havestate to this routine means that an additional
* noop pid rewriting will take place on the first "checkpoint" after
* the game is started or restored, if checkpointing is off.
*/
if (flags.ins_chkpt || havestate) {
/* save the rest of the current game state in the lock file,
* following the original int pid, the current level number,
* and the current savefile name, which should not be subject
* to any internal compression schemes since they must be
* readable by an external utility
*/
fd = open_levelfile(0);
if (fd < 0) {
pline("Cannot open level 0.");
pline("Probably someone removed it.");
done(TRICKED);
return;
}
(void) read(fd, (genericptr_t) &hpid, sizeof(hpid));
if (hackpid != hpid) {
pline("Level 0 pid bad!");
done(TRICKED);
}
(void) close(fd);
fd = create_levelfile(0);
if (fd < 0) {
pline("Cannot rewrite level 0.");
done(TRICKED);
return;
}
(void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid));
if (flags.ins_chkpt) {
int currlev = ledger_no(&u.uz);
(void) write(fd, (genericptr_t) &currlev, sizeof(currlev));
save_savefile_name(fd);
bufon(fd);
savegamestate(fd, WRITE_SAVE);
}
bclose(fd);
}
havestate = flags.ins_chkpt;
}
#endif
#ifdef MFLOPPY
boolean
savelev(fd, lev, mode)
int fd;
xchar lev;
int mode;
{
if (mode & COUNT_SAVE) {
bytes_counted = 0;
savelev0(fd, lev, COUNT_SAVE);
while (bytes_counted > freediskspace(levels))
if (!swapout_oldest())
return FALSE;
}
if (mode & WRITE_SAVE) {
bytes_counted = 0;
/* mode is WRITE_SAVE and possibly FREE_SAVE */
savelev0(fd, lev, mode);
}
fileinfo[lev].where = ACTIVE;
fileinfo[lev].time = moves;
fileinfo[lev].size = bytes_counted;
return TRUE;
}
static void
savelev0(fd,lev,mode)
#else
void
savelev(fd,lev,mode)
#endif
int fd;
xchar lev;
int mode;
{
#ifdef TOS
short tlev;
#endif
if(fd < 0) panic("Save on bad file!"); /* impossible */
#ifdef MFLOPPY
count_only = (mode & COUNT_SAVE);
#else
if(lev >= 0 && lev <= maxledgerno()) level_exists[lev] = TRUE;
#endif
bwrite(fd,(genericptr_t) &hackpid,sizeof(hackpid));
#ifdef TOS
tlev=lev; tlev &= 0x00ff;
bwrite(fd,(genericptr_t) &tlev,sizeof(tlev));
#else
bwrite(fd,(genericptr_t) &lev,sizeof(lev));
#endif
#ifdef RLECOMP
{
/* perform run-length encoding of rm structs */
struct rm *prm, *rgrm;
int x, y;
uchar match;
rgrm = &levl[0][0]; /* start matching at first rm */
match = 0;
for (y = 0; y < ROWNO; y++) {
for (x = 0; x < COLNO; x++) {
prm = &levl[x][y];
if (prm->glyph == rgrm->glyph
&& prm->typ == rgrm->typ
&& prm->seen == rgrm->seen
&& prm->lit == rgrm->lit
&& prm->doormask == rgrm->doormask
&& prm->horizontal == rgrm->horizontal
&& prm->waslit == rgrm->waslit
&& prm->roomno == rgrm->roomno
&& prm->edge == rgrm->edge) {
match++;
if (match > 254) {
match = 254; /* undo this match */
goto writeout;
}
} else {
/* the run has been broken,
* write out run-length encoding */
writeout:
bwrite(fd, (genericptr_t)&match, sizeof(uchar));
bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
/* start encoding again. we have at least 1 rm
* in the next run, viz. this one. */
match = 1;
rgrm = prm;
}
}
}
if (match > 0) {
bwrite(fd, (genericptr_t)&match, sizeof(uchar));
bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
}
}
#else
bwrite(fd,(genericptr_t) levl,sizeof(levl));
#endif /* RLECOMP */
bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves));
bwrite(fd,(genericptr_t) &upstair,sizeof(stairway));
bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway));
bwrite(fd,(genericptr_t) &upladder,sizeof(stairway));
bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway));
bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway));
bwrite(fd,(genericptr_t) &updest,sizeof(dest_area));
bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area));
bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags));
savemonchn(fd, fmon, mode);
save_worm(fd, mode); /* save worm information */
savetrapchn(fd, ftrap, mode);
saveobjchn(fd, fobj, mode);
saveobjchn(fd, billobjs, mode);
save_engravings(fd, mode);
save_rooms(fd);
bwrite(fd,(genericptr_t) doors,sizeof(doors));
savedamage(fd, level.damagelist, mode);
if (mode & FREE_SAVE) {
billobjs = 0;
ftrap = 0;
fmon = 0;
fobj = 0;
}
bflush(fd);
}
#ifdef ZEROCOMP
/* The runs of zero-run compression are flushed after the game state or a
* level is written out. This adds a couple bytes to a save file, where
* the runs could be mashed together, but it allows gluing together game
* state and level files to form a save file, and it means the flushing
* does not need to be specifically called for every other time a level
* file is written out.
*/
#define RLESC '\0' /* Leading character for run of LRESC's */
#define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1)
#ifndef ZEROCOMP_BUFSIZ
#define ZEROCOMP_BUFSIZ BUFSZ
#endif
static unsigned char NEARDATA outbuf[ZEROCOMP_BUFSIZ];
static unsigned short NEARDATA outbufp = 0;
static short NEARDATA outrunlength = -1;
static int NEARDATA bwritefd;
/*dbg()
{
if(!hu) printf("outbufp %d outrunlength %d\n", outbufp,outrunlength);
}*/
static void
bputc(c)
unsigned char c;
{
#ifdef MFLOPPY
bytes_counted++;
if (count_only)
return;
#endif
if (outbufp >= sizeof outbuf) {
(void) write(bwritefd, outbuf, sizeof outbuf);
outbufp = 0;
}
outbuf[outbufp++] = c;
}
/*ARGSUSED*/
void
bufon(fd)
int fd;
{
return;
}
void
bflush(fd) /* flush run and buffer */
register int fd;
{
bwritefd = fd;
if (outrunlength >= 0) { /* flush run */
flushoutrun(outrunlength);
}
if (outbufp) {
#ifdef MFLOPPY
if (!count_only) /* flush buffer */
#endif
(void) write(fd, outbuf, outbufp);
outbufp = 0;
}
/*printf("bflush()"); getret();*/
}
void
bwrite(fd, loc, num)
register int fd;
genericptr_t loc;
register unsigned num;
{
bwritefd = fd;
for (; num; num--, (*(char **)&loc)++) {
if (*((char *)loc) == RLESC) { /* One more char in run */
if (++outrunlength == 0xFF) {
flushoutrun(outrunlength);
}
} else { /* end of run */
if (outrunlength >= 0) { /* flush run */
flushoutrun(outrunlength);
}
bputc(*((char *)loc));
}
}
}
void
bclose(fd)
int fd;
{
if (outbufp)
panic("closing file with buffered data still unwritten");
(void) close(fd);
}
#else /* ZEROCOMP */
static int bw_fd = -1;
static FILE *bw_FILE = 0;
void
bufon(fd)
int fd;
{
#ifdef UNIX
if(bw_fd >= 0)
panic("double buffering unexpected");
bw_fd = fd;
if((bw_FILE = fdopen(fd, "w")) == 0)
panic("buffering of file %d failed", fd);
#endif
}
void
bflush(fd)
int fd;
{
#ifdef UNIX
if(fd == bw_fd) {
if(fflush(bw_FILE) == EOF)
panic("flush of savefile failed!");
}
#endif
return;
}
void
bwrite(fd,loc,num)
register int fd;
register genericptr_t loc;
register unsigned num;
{
#ifdef MFLOPPY
bytes_counted += num;
if (!count_only)
#endif
{
#ifdef UNIX
if(fd != bw_fd)
panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
if(fwrite(loc, (int)num, 1, bw_FILE) != 1)
/* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
#else
# if defined(BSD) || defined(ULTRIX)
if(write(fd, loc, (int)num) != (int)num)
# else /* e.g. SYSV, __TURBOC__ */
if(write(fd, loc, num) != num)
# endif
#endif
{
if(!hu) panic("cannot write %u bytes to file #%d", num, fd);
else terminate(1);
}
}
}
void
bclose(fd)
int fd;
{
bflush(fd);
#ifdef UNIX
if (fd == bw_fd) {
(void) fclose(bw_FILE);
bw_fd = -1;
bw_FILE = 0;
return;
}
#endif
(void) close(fd);
}
#endif /* ZEROCOMP */
static void
savelevchn(fd, mode)
register int fd, mode;
{
int cnt = 0;
s_level *tmplev, *tmplev2;
for(tmplev = sp_levchn; tmplev; tmplev = tmplev->next) cnt++;
bwrite(fd, (genericptr_t) &cnt, sizeof(int));
for(tmplev = sp_levchn; tmplev; tmplev = tmplev2) {
tmplev2 = tmplev->next;
bwrite(fd, (genericptr_t) tmplev, sizeof(s_level));
if (mode & FREE_SAVE)
free((genericptr_t) tmplev);
}
}
static void
savedamage(fd, damageptr, mode)
register int fd, mode;
register struct damage *damageptr;
{
register struct damage *tmp_dam;
unsigned int xl = 0;
for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next)
xl++;
bwrite(fd, (genericptr_t) &xl, sizeof(xl));
while (xl--) {
bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr));
tmp_dam = damageptr;
damageptr = damageptr->next;
if (mode & FREE_SAVE)
free((genericptr_t)tmp_dam);
}
if (mode & FREE_SAVE)
level.damagelist = 0;
}
static void
saveobjchn(fd,otmp,mode)
register int fd, mode;
register struct obj *otmp;
{
register struct obj *otmp2;
unsigned int xl;
int minusone = -1;
while(otmp) {
otmp2 = otmp->nobj;
xl = otmp->onamelth;
bwrite(fd, (genericptr_t) &xl, sizeof(int));
bwrite(fd, (genericptr_t) otmp, xl + sizeof(struct obj));
if (Is_container(otmp) || otmp->otyp == STATUE)
saveobjchn(fd,otmp->cobj,mode);
if (mode & FREE_SAVE)
dealloc_obj(otmp);
otmp = otmp2;
}
bwrite(fd, (genericptr_t) &minusone, sizeof(int));
}
static void
savemonchn(fd,mtmp,mode)
register int fd, mode;
register struct monst *mtmp;
{
register struct monst *mtmp2;
unsigned int xl;
int minusone = -1;
struct permonst *monbegin = &mons[0];
bwrite(fd, (genericptr_t) &monbegin, sizeof(monbegin));
while(mtmp) {
mtmp2 = mtmp->nmon;
#ifdef MUSE
if (mtmp->mw && mtmp->mw != mtmp->minvent) sort_mwep(mtmp);
#endif
xl = mtmp->mxlth + mtmp->mnamelth;
bwrite(fd, (genericptr_t) &xl, sizeof(int));
bwrite(fd, (genericptr_t) mtmp, xl + sizeof(struct monst));
if(mtmp->minvent) saveobjchn(fd,mtmp->minvent,mode);
if (mode & FREE_SAVE)
dealloc_monst(mtmp);
mtmp = mtmp2;
}
bwrite(fd, (genericptr_t) &minusone, sizeof(int));
}
static void
savetrapchn(fd,trap,mode)
register int fd,mode;
register struct trap *trap;
{
register struct trap *trap2;
while(trap) {
trap2 = trap->ntrap;
bwrite(fd, (genericptr_t) trap, sizeof(struct trap));
if (mode & FREE_SAVE)
dealloc_trap(trap);
trap = trap2;
}
bwrite(fd, (genericptr_t)nulls, sizeof(struct trap));
}
#ifdef TUTTI_FRUTTI
/* save all the fruit names and ID's; this is used only in saving whole games
* (not levels) and in saving bones levels. When saving a bones level,
* we only want to save the fruits which exist on the bones level; the bones
* level routine marks nonexistent fruits by making the fid negative.
*/
void
savefruitchn(fd, mode)
register int fd, mode;
{
register struct fruit *f2, *f1;
f1 = ffruit;
while(f1) {
f2 = f1->nextf;
if (f1->fid >= 0) {
bwrite(fd, (genericptr_t) f1, sizeof(struct fruit));
}
if (mode & FREE_SAVE)
dealloc_fruit(f1);
f1 = f2;
}
bwrite(fd, (genericptr_t)nulls, sizeof(struct fruit));
}
#endif
static void
savegenoinfo(fd)
register int fd;
{
register int i;
unsigned genolist[NUMMONS];
for (i = 0; i < NUMMONS; i++)
genolist[i] = mons[i].geno;
bwrite(fd, (genericptr_t) genolist, sizeof(genolist));
}
#ifdef MFLOPPY
boolean
swapin_file(lev)
int lev;
{
char to[PATHLEN], from[PATHLEN];
Sprintf(from, "%s%s", permbones, alllevels);
Sprintf(to, "%s%s", levels, alllevels);
set_levelfile_name(from, lev);
set_levelfile_name(to, lev);
while (fileinfo[lev].size > freediskspace(to))
if (!swapout_oldest())
return FALSE;
# ifdef WIZARD
if (wizard) {
pline("Swapping in `%s'", from);
wait_synch();
}
# endif
copyfile(from, to);
(void) unlink(from);
fileinfo[lev].where = ACTIVE;
return TRUE;
}
static boolean
swapout_oldest() {
char to[PATHLEN], from[PATHLEN];
int i, oldest;
long oldtime;
if (!ramdisk)
return FALSE;
for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++)
if (fileinfo[i].where == ACTIVE
&& (!oldtime || fileinfo[i].time < oldtime)) {
oldest = i;
oldtime = fileinfo[i].time;
}
if (!oldest)
return FALSE;
Sprintf(from, "%s%s", levels, alllevels);
Sprintf(to, "%s%s", permbones, alllevels);
set_levelfile_name(from, oldest);
set_levelfile_name(to, oldest);
# ifdef WIZARD
if (wizard) {
pline("Swapping out `%s'.", from);
wait_synch();
}
# endif
copyfile(from, to);
(void) unlink(from);
fileinfo[oldest].where = SWAPPED;
return TRUE;
}
static void
copyfile(from, to)
char *from, *to;
{
# ifdef TOS
if (_copyfile(from, to))
panic("Can't copy %s to %s", from, to);
# else
char buf[BUFSIZ]; /* this is system interaction, therefore
* BUFSIZ instead of NetHack's BUFSZ */
int nfrom, nto, fdfrom, fdto;
if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0)
panic("Can't copy from %s !?", from);
if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0)
panic("Can't copy to %s", to);
do {
nfrom = read(fdfrom, buf, BUFSIZ);
nto = write(fdto, buf, nfrom);
if (nto != nfrom)
panic("Copyfile failed!");
} while (nfrom == BUFSIZ);
(void) close(fdfrom);
(void) close(fdto);
# endif /* TOS */
}
void
co_false() /* see comment in bones.c */
{
count_only = FALSE;
return;
}
#endif /* MFLOPPY */
/*save.c*/